using CfgTable;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Onigao.Logic;

namespace IQIGame.Onigao.GamePlay
{
    public class MainCityNormalEntity : MainCityRealityEntity
    {
        public override uint MaxStore => 100;

        private CfgMainCityNpc _cfgMainCityNpc;
        private bool _isExistActiveQuest;
        private MainCityEntityEffectView _questMarkEffect;
        private MainCityServiceManager _serviceMgr;
        private float _updateTimer;
        private float _accumulatedDeltaTime;

        public bool isIndicatorOnMe { get; private set; }
        public DynMainCityEntity dynNormalEntity => dynEntity as DynMainCityEntity;

        public override string name => _cfgMainCityNpc.Name;

        public override int viewRange => dynNormalEntity.entityConfig.viewRange;

        public override int viewAngle => dynNormalEntity.entityConfig.viewAngle;
        public override float defaultMeterSpeed => _cfgEntity.DefaultSpeed.CentimetreToMetre();
        public override bool isActive => dynNormalEntity.isActive;

        protected override bool isRecastAgent => dynNormalEntity.isObstacleActive
            && dynNormalEntity.entityConfig.obstacle != null
            && !dynNormalEntity.entityConfig.obstacle.invalid
            && !dynNormalEntity.entityConfig.obstacle.isClient
            && !dynNormalEntity.entityConfig.obstacle.isStatic;
        /// <summary>
        /// 死亡动画播放完成，如果该值为true，dynNormalEntity.isActive一定是false
        /// </summary>
        public bool isPlayingDieAnimation { get; internal set; }

        public void Init(DynMainCityEntity dynEntity)
        {
            this.dynEntity = dynEntity;
            _cfgMainCityNpc = TableCenter.mainCityNpc.Get(dynEntity.entityConfig.npcCid);
            _cfgEntity = TableCenter.physicalEntity.Get(_cfgMainCityNpc.EntityId);
            if (dynEntity.entityConfig.paramMap.TryGetValue(MainCityEntityDynParamType.Service, out var param))
            {
                _serviceMgr = ClassPool<MainCityServiceManager>.Get();
                _serviceMgr.Init(this, param as MainCityDynParamService);
            }
            AddComponentWithPool<MainCityAnimationComponent>(ETComponentType.EntityAnimation);
            AddComponentWithPool<MainCityMoveComponent>(ETComponentType.EntityMove);
            AddComponentWithPool<EntityBindPointComponent>(ETComponentType.EntityBindPoint);
            AddComponentWithPool<EntityUIViewComponent>(ETComponentType.EntityUIView);
        }

        public override void OnUpdate(float deltaTime)
        {
            _updateTimer += deltaTime;
            _accumulatedDeltaTime += deltaTime;
            float interval = _objectEntity == null ? MainCityConst.EntityUpdateIntervalWithoutModel : MainCityConst.EntityUpdateIntervalNormal;
            if (interval == 0 || _updateTimer > interval)
            {
                _updateTimer -= interval;
                var accumulatedDeltaTime = _accumulatedDeltaTime;
                _accumulatedDeltaTime = 0;
                base.OnUpdate(accumulatedDeltaTime);
            }
        }

        protected override void CreateTransformAgent()
        {
            var agent = ClassPool.Get<NullableTransformAgent>();
            agent.entity = this;

            _transform = agent;
        }

        public override void OnEntityBirth()
        {
            base.OnEntityBirth();
            StartAI();
        }

        private void StartAI()
        {
            if (!string.IsNullOrEmpty(this.dynNormalEntity.behavScriptName))
            {
                var bsCom = this.AddComponentWithPool<EntityBehavScriptComponent>(ETComponentType.EntityBehavScript);
                bsCom.Play(this.dynNormalEntity.behavScriptName);
            }
        }

        /// <summary>
        /// 刷新任务状态
        /// </summary>
        public override void RefreshQuestState()
        {
            base.RefreshQuestState();
            if (dynNormalEntity.entityConfig.paramMap.TryGetValue(MainCityEntityDynParamType.QuestList, out var dynParam))
            {
                var quests = (dynParam as MainCityDynParamQuest).offerQuests;
                foreach (int cid in quests)
                {
                    if (QuestModule.Instance.IsAcceptable(cid, this))
                    {
                        SetQuestState(true).Forget();
                        return;
                    }
                }
            }
            SetQuestState(false).Forget();
        }

        /// <summary>
        /// 设置任务状态
        /// </summary>
        /// <param name="isExistActiveQuest"></param>
        /// <returns></returns>
        private async UniTaskVoid SetQuestState(bool isExistActiveQuest)
        {
            _isExistActiveQuest = isExistActiveQuest;
            if (isIndicatorOnMe) //如果头上已经显示交互指示器，当前一定不会有叹号显示
            {
                return;
            }
            await SetQuestMarkActive(isExistActiveQuest);
        }

        /// <summary>
        /// 显示或隐藏叹号特效
        /// </summary>
        /// <param name="isActive"></param>
        /// <returns></returns>
        private async UniTask SetQuestMarkActive(bool isActive)
        {
            if (isActive && _questMarkEffect == null)
            {
                _questMarkEffect = await MainCityModule.Instance.mainController.regionCtrl.effectCtrl.ShowEffectOnPoint(this, EntityBindPointCommonType.Top, ViewEntityConst.QuestMarkEffectResId);
            }
            else if (!isActive && _questMarkEffect != null)
            {
                MainCityModule.Instance.mainController.regionCtrl.effectCtrl.HideEffect(_questMarkEffect);
                _questMarkEffect = null;
            }
        }

        /// <summary>
        /// 头顶交互指示器改变
        /// </summary>
        /// <param name="isIndicatorOnMe"></param>
        public override void OnIndicatorChange(bool isIndicatorOnMe)
        {
            base.OnIndicatorChange(isIndicatorOnMe);
            if (_isExistActiveQuest) //如果当前有可接取任务，需根据指示器是否在头上改变任务叹号的显示
            {
                //任务叹号和指示器互斥，且指示器优先级更高
                SetQuestMarkActive(!isIndicatorOnMe).Forget();
            }
        }

        protected override string GetEntityLoadPath()
        {
            return PathConstant.GetEntityLevelPrefabPath(_cfgEntity.EntityAsset);
        }

        /// <summary>
        /// 触发实体的服务
        /// </summary>
        /// <param name="triggerType">触发器类型</param>
        /// <param name="dynamicObjParam">引用类型通用动态参数</param>
        /// <param name="dynamicValueTypePram">值类型通用动态参数</param>
        /// <returns>是否有执行被运行</returns>
        public override ServiceNonLevel TryTriggerService(MainCityTriggerType triggerType, out bool anyExecDone, object dynamicObjParam = null, TrigValueTypeParam dynamicValueTypePram = default)
        {
            anyExecDone = false;
            if (MainCityModule.Instance.mainController.regionCtrl.entityCtrl.playerAvatarEntity.dynPlayerAvatarEntity.isOccupied)
            {
                return null;
            }
            if (_serviceMgr == null)
            {
                return null;
            }
            //注意TryTrigger并没有实际的执行逻辑，只判断触发，条件，并返回是否有执行需要处理
            var triggeredService = _serviceMgr.TryTrigger(triggerType, out anyExecDone, dynamicObjParam, dynamicValueTypePram);
            //如果有，则发送触发器索引给服务器
            if (triggeredService != null)
            {
                SendTriggerService(triggeredService.index).Forget();
            }
            return triggeredService;
        }

        private async UniTaskVoid SendTriggerService(int index)
        {
            var result = await MainCityModule.NetCore.CS_requestExeService(dynNormalEntity.id, index);
        }

        public override void OnReset()
        {
            base.OnReset();
            _cfgMainCityNpc = null;
            _isExistActiveQuest = false;
            _questMarkEffect = null;
            isIndicatorOnMe = false;
            if (_serviceMgr != null)
            {
                ClassPool<MainCityServiceManager>.Put(_serviceMgr);
                _serviceMgr = null;
            }
            _updateTimer = 0;
            _accumulatedDeltaTime = 0;
        }
    }
}
